iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0

ERC-721

又稱非同值化代幣(Non-Fungible Token),簡稱NFT,實際上也是有一套實作的標準,知名項目如無聊猿(BAYC)或AUZKI等皆是,與ERC-20不同的是每一個代幣都有自己的tokenID且都不同於另一個代幣,多數的ERC-721都只在儲存代幣及持有者在鍊上,而其資料則存於Metadata在其他網址和所代表的圖片或等等則儲存在其指向的網址。需同時實作ERC-721及ERC-165,這些標準及其他ERC都可以在Openzeppelin查看或引入。(以下為Solidity)

可選:

// ERC-721Metadata
//代幣名稱
function name()externalviewreturns (string _name);
//代幣標示
function symbol()externalviewreturns (string _symbol);
//NFT的資料
function tokenURI(uint256 _tokenId)externalviewreturns (string);
// ERC-165 
// 檢查是否實現某個interface
function supportsInterface(bytes4 interfaceId) external pure returns (bool){
    return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC165).interfaceId;
}

必備:

// ERC-721
// 記錄事件
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
//紀錄地址擁有的NFT數量
mapping (address => uint) _balance;
//紀錄NFT是屬於哪個地址
mapping (uint => address) _owner;
//紀錄NFT有授權的地址
mapping (uint => address) _approve;
//紀錄地址全部NFT有授權的地址
mapping (address => mapping(address => bool)) _approveAll;
//查詢數量
function balanceOf(address owner) public view returns (uint256){
    require(owner != address(0),"Error address can not be 0");
    return _balance[owner];
}
//查詢擁有者地址
function ownerOf(uint256 tokenId) public view returns (address){
    address owner = _owner[tokenId];
    require(owner != address(0),"Error address can not be 0");
    return owner;
}
//授權
function approve(address to, uint256 tokenId) public{
    address owner = _owner[tokenId];
    require(owner != to,"Error to == owner");
    require(owner == msg.sender ,"Error");
    _approve[tokenId] = to;
    emit Approval(owner, to, tokenId);
}
//查詢有授權的地址
function getApproved(uint256 tokenId) public view returns (address){
    address owner = _owner[tokenId];
    require(owner != address(0),"Error owner can not be 0");
    return _approve[tokenId];
}
//授權全部
function setApprovalForAll(address operator, bool _approved) public{
    require(msg.sender != operator,"Error owner == poerator");
    _approveAll[msg.sender][operator]=_approved;
    emit ApprovalForAll(msg.sender, operator, _approved);
}
//查詢是否授權全部
function isApprovedForAll(address owner, address operator) public view returns (bool){
    return _approveAll[owner][operator];
}
//轉移NFT
function transferFrom(address from, address to, uint256 tokenId) public{
    address owner =_owner[tokenId];
    require(owner == from ,"Error");
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender) || getApproved(tokenId) == msg.sender,"Error");
    delete _approve[tokenId];
    _balance[from] -=1;
    _balance[to] +=1;
    _owner[tokenId]=to;
    emit Transfer(from, to, tokenId);
}
//安全轉移(有require確認接收地址是否合法地址)
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {
    transferFrom(from, to, tokenId);
    require(_checkOnERC721Received(from, to, tokenId, data),"Error: ERC721Receiver is not implmeneted");
}
//鑄造NFT
function mint(address to, uint256 tokenId) public {
    require(to != address(0), "ERROR: Mint to address 0");
    address owner = _owner[tokenId];
    //檢查是否重複
    require(owner == address(0), "ERROR: tokenId existed");
    _balance[to] += 1;
    _owner[tokenId] = to;
    emit Transfer(address(0), to, tokenId);
}
//安全轉移(有require確認接收地址是否合法地址)
function safemint(address to, uint256 tokenId, bytes memory data) public {
    mint(to, tokenId);
    require(_checkOnERC721Received(address(0), to, tokenId, data), "ERROR: ERC721Receiver is not implmeneted");
}
//燒毀NFT
function burn(uint256 tokenId) public {
    address owner = _owner[tokenId];
    require(msg.sender == owner, "ERROR: only owner can burn");
    _balance[owner] -= 1;
    delete _owner[tokenId];
    delete _approve[tokenId];
    emit Transfer(owner, address(0), tokenId);
}
//查詢數量
function balanceOf(address owner) public view returns (uint256){
    require(owner != address(0),"Error address can not be 0");
    return _balance[owner];
}
//查詢擁有者地址
function ownerOf(uint256 tokenId) public view returns (address){
    address owner = _owner[tokenId];
    require(owner != address(0),"Error address can not be 0");
    return owner;
}
//授權
function approve(address to, uint256 tokenId) public{
    address owner = _owner[tokenId];
    require(owner != to,"Error to == owner");
    require(owner == msg.sender ,"Error");
    _approve[tokenId] = to;
    emit Approval(owner, to, tokenId);
}
//查詢有授權的地址
function getApproved(uint256 tokenId) public view returns (address){
    address owner = _owner[tokenId];
    require(owner != address(0),"Error owner can not be 0");
    return _approve[tokenId];
}
//授權全部
function setApprovalForAll(address operator, bool _approved) public{
    require(msg.sender != operator,"Error owner == poerator");
    _approveAll[msg.sender][operator]=_approved;
    emit ApprovalForAll(msg.sender, operator, _approved);
}
//查詢是否授權全部
function isApprovedForAll(address owner, address operator) public view returns (bool){
    return _approveAll[owner][operator];
}
//轉移NFT
function transferFrom(address from, address to, uint256 tokenId) public{
    address owner =_owner[tokenId];
    require(owner == from ,"Error");
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender) || getApproved(tokenId) == msg.sender,"Error");
    delete _approve[tokenId];
    _balance[from] -=1;
    _balance[to] +=1;
    _owner[tokenId]=to;
    emit Transfer(from, to, tokenId);
}
//安全轉移(有require確認接收地址是否合法地址)
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public {
    transferFrom(from, to, tokenId);
    require(_checkOnERC721Received(from, to, tokenId, data),"Error: ERC721Receiver is not implmeneted");
}
//鑄造NFT
function mint(address to, uint256 tokenId) public {
    require(to != address(0), "ERROR: Mint to address 0");
    address owner = _owner[tokenId];
    //檢查是否重複
    require(owner == address(0), "ERROR: tokenId existed");
    _balance[to] += 1;
    _owner[tokenId] = to;
    emit Transfer(address(0), to, tokenId);
}
//安全轉移(有require確認接收地址是否合法地址)
function safemint(address to, uint256 tokenId, bytes memory data) public {
    mint(to, tokenId);
    require(_checkOnERC721Received(address(0), to, tokenId, data), "ERROR: ERC721Receiver is not implmeneted");
}
//燒毀NFT
function burn(uint256 tokenId) public {
    address owner = _owner[tokenId];
    require(msg.sender == owner, "ERROR: only owner can burn");
    _balance[owner] -= 1;
    delete _owner[tokenId];
    delete _approve[tokenId];
    emit Transfer(owner, address(0), tokenId);
}

其中代碼可以再自行定義一些功能。


上一篇
穩定幣
下一篇
預言機
系列文
Web3新手初探筆記32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言